/**
 * @file application
 * @author shenli
 */

var finalhandler = require('finalhandler');
var methods =  require('methods');
var Router = require('./router');
var View = require('./view');
var middleware = require('./middleware/init');
var query = require('./middleware/query');
var compileQueryParser = require('./utils').compileQueryParser;
var flatten = require('array-flatten');

var slice = Array.prototype.slice;

var app = module.exports = {};

app.init = function init() {
    this.settings = {};
    this.cache = {};
    this.engine = {};
    this.defaultConfiguration();
};

app.defaultConfiguration = function () {
    var env = process.env.NODE_ENV || 'development';

    this.set('env', env);
    this.set('queryParser', 'extended');
    this.on('mount', function (parent) {

    });

    this.locals = {};

    this.mountpath = '/';

    this.locals.settings = this.settings;

    this.set('view', View);
};

app.set = function (setting, val) {
    if (arguments.length === 1) {
        // app.get(setting)
        return this.settings[setting];
    }

    this.settings[setting] = val;

    switch (setting) {
        case 'queryParser':
            this.set('query parser fn', compileQueryParser(val));
            break;
        default:
            break;
    }

    return this;
};


app.lazyRouter = function () {
    if (!this._router) {
        this._router = new Router({
            strict: false
        });
        this._router.use(query(this.get('query parser fn')));
        this._router.use(middleware.init(this));
    }
};

app.handle = function (req, res, callback) {
    var router = this._router;
    var done = callback || finalhandler(req, res, {
        env: this.get('env')
    });

    if (!router) {
        debug('no routes defined on app');
        done();
        return;
    }

    router.handle(req, res, done);
};

app.use = function (fn) {
    var offset = 0;
    var path = '/';

    if (typeof fn !== 'function') {
        path = fn;
        offset = 1;
    }

    var fns = flatten(slice.call(arguments, offset));

    if (fns.length === 0) {
        throw new TypeError('app.use() requires middleware functions');
    }

    this.lazyRouter();
    var router = this._router;

    fns.forEach(function (fn) {
        // non-express app
        if (!fn || !fn.handle || !fn.set) {
          return router.use(path, fn);
        }

        debug('.use app under %s', path);
        fn.mountpath = path;
        fn.parent = this;

        router.use(path, function (req, res, next) {
            var orig = req.app;
            fn.handle(req, res, function (err){
                req.__proto__ = orig.req;
                res.__proto__ = orig.res;
                next(err);
            });
        });

        fn.emit('mount', this);
    }, this);

    return this;
};

app.route = function route(path) {
  this.lazyrouter();
  return this._router.route(path);
};


app.enabled = function (setting) {
    return Boolean(this.set(setting));
};

methods.forEach(function (method) {
    app[method] = function (path) {
        if (method === 'get' && arguments.length === 1) { // 参数只有一个，认为是获取settings
            return this.set(path);
        }

        this.lazyRouter();

        var route = this._router.route(path);

        route[method].apply(route, slice.call(arguments, 1));
        return this;
    }
});
